﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Routing;
using System.Web.Mvc;
using System.IO;
using System.Web.Script.Serialization;
using Vit.Caching;
using Vit.Web.Models;

namespace Vit.Web.Services
{
    public class LocalizationService : ILocalizationService
    {
        private const string GeoIPDataFile = "~/Localization/GeoIP.dat";
        private const string ResouceFile = "resources.js";
        private ICacheManager cache;
        private IAccountService account;
        private ISiteService siteSvr;

        public LocalizationService(ISiteService siteSvr, IAccountService account, ICacheManager cache)
        {
            this.siteSvr = siteSvr;
            this.account = account;
            this.cache = cache;
        }

        private string GetLocalizationItem(string area, string resourceName)
        {
            User user = account.GetCurrentUser();
            WebSite site = siteSvr.GetCurrentSite();

            if (string.IsNullOrEmpty(area))
                area = site.RouteData == null ? "main" : (site.RouteData.DataTokens["area"] as string ?? "main");

            string cacheName = string.Format("{0}_{1}_{2}_resources",
                site.Name,
                user.Locale.Language,
                area);
            LocaleItem locale = cache.GetData(cacheName) as LocaleItem;
            if (locale != null && locale.Items.ContainsKey(resourceName))
                return locale.Items[resourceName];

            if (locale == null)
            {
                foreach (string loc in LocalizationLocationFormats)
                {
                    string file = string.Format(loc, site.Name, area, user.Locale.Language);
                    string physicalFile = HttpContext.Current.Server.MapPath(file);
                    if (File.Exists(physicalFile))
                    {
                        using (StreamReader sr = new StreamReader(physicalFile))
                        {
                            string jsonContent = sr.ReadToEnd();
                            if (string.IsNullOrEmpty(jsonContent))
                                continue;

                            if (jsonContent.StartsWith("{") == false)
                                jsonContent = jsonContent.Substring(jsonContent.IndexOf("{"));
                            if (jsonContent.EndsWith("}") == false)
                                jsonContent = jsonContent.Substring(0, jsonContent.LastIndexOf("}") + 1);

                            JavaScriptSerializer ser = new JavaScriptSerializer();
                            locale = ser.Deserialize<LocaleItem>(jsonContent);
                            cache.Add(cacheName, locale, new string[] { "Localization" }, TimeSpan.Zero, DateTime.MaxValue);
                            break;
                        }
                    }
                }
            }

            if (locale == null)
            {
                cacheName = string.Format("{0}_{1}_{2}_resources",
                    site.Name,
                    user.Locale.Language,
                    "main");
                locale = cache.GetData(cacheName) as LocaleItem;
            }

            if (locale != null && locale.Items.ContainsKey(resourceName))
                return locale.Items[resourceName];

            return resourceName;
        }

        #region ILocalizationService Members

        public string Resource(string resourceName, params object[] paras)
        {
            string value = GetLocalizationItem(null, resourceName);
            return string.Format(value, paras);
        }

        public string Resource(string area, string resourceName, params object[] paras)
        {
            string value = GetLocalizationItem(area, resourceName);
            return string.Format(value, paras);
        }

        private GeoCountry geoCountry;
        public Locale GetLocaleByGeoIP()
        {
            if (geoCountry == null)
                geoCountry = new GeoCountry(HttpContext.Current.Server.MapPath(GeoIPDataFile));

            Locale loc = new Locale();

            string host = HttpContext.Current.Request.UserHostAddress;
            loc.Language = geoCountry.GetCountryCode(host);
            loc.Country = geoCountry.GetCountryName(host);

            return loc;
        }

        #endregion

        private static string[] localizationLocationFormats;
        public static string[] LocalizationLocationFormats
        {
            get
            {
                if (localizationLocationFormats == null)
                {
                    localizationLocationFormats = new string[] {
                        "~/Sites/{0}/Areas/{1}/Views/Shared/resources.{2}.js",
                        "~/Sites/{0}/Views/Shared/resources.{2}.js",
                        "~/Areas/{1}/Views/Shared/resources.{2}.js",
                        "~/Views/Shared/resources.{2}.js",
                        "~/Sites/{0}/Areas/{1}/Views/Shared/resources.js",
                        "~/Sites/{0}/Views/Shared/resources.js",
                        "~/Areas/{1}/Views/Shared/resources.js",
                        "~/Views/Shared/resources.js"
                    };
                }
                return localizationLocationFormats;
            }
        }
    }
}
